๊ฐ๋ฐ์๋ฅผ ์ํ ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ Manifest V3๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๊ธฐ ์ํ ํฌ๊ด์ ์ธ ๊ฐ์ด๋์ ๋๋ค. JavaScript API ๋ณ๊ฒฝ ์ฌํญ ๋ฐ ํจ๊ณผ์ ์ธ ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต์ ์ค์ ์ ๋ก๋๋ค.
์ ํ ํ์: ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ Manifest V3 JavaScript API ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต
๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ ํ๊ฒฝ์ ๋์์์ด ์งํํ๊ณ ์์ต๋๋ค. ์ต๊ทผ ๋ช ๋ ๋์ ๊ฐ์ฅ ํฐ ๋ณํ ์ค ํ๋๋ Manifest V3 (MV3)์ ๋์ ์ ๋๋ค. Google Chrome์์ ์์๋์์ง๋ง ๋ค๋ฅธ Chromium ๊ธฐ๋ฐ ๋ธ๋ผ์ฐ์ ์ Firefox์ ์ ์ ๋ ์ํฅ์ ๋ฏธ์น๋ ์ด ์ ๋ฐ์ดํธ๋ ์ ์ธ๊ณ ์ฌ์ฉ์์ ๋ณด์, ๊ฐ์ธ ์ ๋ณด ๋ณดํธ ๋ฐ ์ฑ๋ฅ ํฅ์์ ๋ชฉํ๋ก ํฉ๋๋ค. ๊ฐ๋ฐ์์๊ฒ ์ด ์ ํ์ ํนํ JavaScript API์ ๊ด๋ จํ์ฌ ๋ณ๊ฒฝ ์ฌํญ์ ๋ํ ๊น์ ์ดํด๊ฐ ํ์ํฉ๋๋ค. ์ด ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ ๊ธฐ์กด Manifest V2 ํ์ฅ ํ๋ก๊ทธ๋จ์ MV3๋ก ํจ๊ณผ์ ์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๊ณ , ์ ์๋ฌผ์ด ์๋ก์ด ํ๊ฒฝ์์ ๊ณ์ ์๋ํ๊ณ ๋ฒ์ฐฝํ ์ ์๋๋ก ํ๋ ๋ฐ ํ์ํ ์ง์๊ณผ ์ ๋ต์ ์ ๊ณตํฉ๋๋ค.
Manifest V3์ ํต์ฌ ๋ณ๊ฒฝ ์ฌํญ ์ดํด
Manifest V3๋ ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ์๋ํ๋ ๋ฐฉ์์ ๊ทผ๋ณธ์ ์ผ๋ก ์ฌ๊ณ ํ๋ ๊ฒ์ ๋๋ค. ์ด๋ฌํ ๋ณํ์ ์ฃผ์ ์๋๋ ฅ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ํฅ์๋ ๋ณด์: MV3๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ์คํํ ์ ์๋ ์ฝ๋ ์ ํ๊ณผ ์น ํ์ด์ง์ ์ํธ ์์ฉํ ์ ์๋ ๋ฐฉ์์ ์ ํํ๋ ๋ ์๊ฒฉํ ๋ณด์ ์ ์ฑ ์ ๋์ ํฉ๋๋ค.
- ๊ฐ์ ๋ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ: ์๋ก์ด ๋ชจ๋ธ์ ํน์ ๋ฏผ๊ฐํ API์ ๋ํ ์ก์ธ์ค๋ฅผ ์ ํํ๊ณ ๋ ํฌ๋ช ํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์ฅ๋ คํ์ฌ ์ฌ์ฉ์ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ๋ฅผ ๊ฐ์กฐํฉ๋๋ค.
- ๋ ๋์ ์ฑ๋ฅ: ์ผ๋ถ ๊ตฌํ ์ํคํ ์ฒ๋ฅผ ๋ฒ์ด๋ MV3๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ๋ธ๋ผ์ฐ์ ์๋ ๋ฐ ๋ฆฌ์์ค ์๋น์ ๋ฏธ์น๋ ์ฑ๋ฅ ์ํฅ์ ์ค์ด๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
JavaScript API ๊ด์ ์์ ๊ฐ์ฅ ํฐ ์ํฅ์ ๋ฏธ์น๋ ๋ณ๊ฒฝ ์ฌํญ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง๋ฅผ ๋์ฒดํ๋ ์๋น์ค ์์ปค: ์๊ตฌ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง ๋ชจ๋ธ์ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์๋น์ค ์์ปค๋ก ๋์ฒด๋๊ณ ์์ต๋๋ค. ์ฆ, ๋ฐฑ๊ทธ๋ผ์ด๋ ๋ก์ง์ ํ์ํ ๋๋ง ์คํ๋๋ฏ๋ก ์ํ ๊ด๋ฆฌ ๋ฐ ์ด๋ฒคํธ ์ฒ๋ฆฌ์ ๋ํ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ด ํ์ํ๋ฉฐ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
- Web Request API ์์ : ๋คํธ์ํฌ ์์ฒญ ๊ฐ๋ก์ฑ๊ธฐ์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ๊ฐ๋ ฅํ `chrome.webRequest` API๋ MV3์์ ํฌ๊ฒ ์ ํ๋ฉ๋๋ค. ๋ ์ ์ฐํ์ง๋ง ๊ฐ์ธ ์ ๋ณด๋ฅผ ๋ ์ ๋ณดํธํ๊ณ ์ฑ๋ฅ์ด ๋ฐ์ด๋ `declarativeNetRequest` API๋ก ๋์ฒด๋ฉ๋๋ค.
- ์ฝํ ์ธ ์คํฌ๋ฆฝํธ ์คํ ๋ณ๊ฒฝ ์ฌํญ: ์ฝํ ์ธ ์คํฌ๋ฆฝํธ๋ ์ ์ง๋์ง๋ง, ์คํ ์ปจํ ์คํธ์ ๊ธฐ๋ฅ์ด ๊ฐ์ ๋์์ต๋๋ค.
- `eval()` ๋ฐ `new Function()` ์ ๊ฑฐ: ๋ณด์์์ ์ด์ ๋ก `eval()` ๋ฐ `new Function()`์ ๋ ์ด์ ํ์ฅ ์ฝ๋์์ ํ์ฉ๋์ง ์์ต๋๋ค.
์ฃผ์ JavaScript API ๋ง์ด๊ทธ๋ ์ด์ ๋ฐ ์ ๋ต
์ฃผ์ JavaScript API ๋ง์ด๊ทธ๋ ์ด์ ์ ์ธ๋ถ ์ฌํญ์ ์ดํด๋ณด๊ณ ๊ฐ๊ฐ์ ๋ํ ํจ๊ณผ์ ์ธ ์ ๋ต์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
1. ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ์์ ์๋น์ค ์์ปค๋ก์ ๋ง์ด๊ทธ๋ ์ด์
์ด๊ฒ์ ์๋ง๋ ๊ฐ์ฅ ๊ทผ๋ณธ์ ์ธ ๋ณํ์ผ ๊ฒ์ ๋๋ค. Manifest V2 ํ์ฅ ํ๋ก๊ทธ๋จ์ ํญ์ ์คํ ์ค์ธ ์๊ตฌ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง์ ์์กดํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์ต๋๋ค. Manifest V3๋ ์๋น์ค ์์ปค๋ฅผ ๋์ ํ๋๋ฐ, ์ด๋ ์ด๋ฒคํธ ๊ธฐ๋ฐ์ด๋ฉฐ ์ด๋ฒคํธ(์: ํ์ฅ ํ๋ก๊ทธ๋จ ์ค์น, ๋ธ๋ผ์ฐ์ ์์ ๋๋ ์ฝํ ์ธ ์คํฌ๋ฆฝํธ์ ๋ฉ์์ง)์ ์ํด ํธ๋ฆฌ๊ฑฐ๋ ๋๋ง ์คํ๋ฉ๋๋ค.
๋ณ๊ฒฝ ์ด์ ๋ ๋ฌด์์ ๋๊น?
์๊ตฌ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง๋ ํนํ ๋ง์ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ํ์ฑํ๋ ๊ฒฝ์ฐ ์๋นํ ๋ฆฌ์์ค๋ฅผ ์๋นํ ์ ์์ต๋๋ค. ์๋น์ค ์์ปค๋ ํ์ฅ ํ๋ก๊ทธ๋จ ๋ก์ง์ด ํ์ํ ๊ฒฝ์ฐ์๋ง ์คํ๋๋๋ก ๋ณด์ฅํ๋ ๋ณด๋ค ํจ์จ์ ์ธ ๋ชจ๋ธ์ ์ ๊ณตํ์ฌ ๋ธ๋ผ์ฐ์ ์์ ์๋๋ฅผ ๋์ด๊ณ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ค์ ๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต:
- ์ด๋ฒคํธ ๊ธฐ๋ฐ ๋ก์ง: ๋ฐฑ๊ทธ๋ผ์ด๋ ๋ก์ง์ ์ด๋ฒคํธ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ ์ค๊ณํฉ๋๋ค. ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํฌ๋ฆฝํธ๊ฐ ํญ์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค๊ณ ๊ฐ์ ํ๋ ๋์ ํน์ ์ด๋ฒคํธ๋ฅผ ์์ ๋๊ธฐํฉ๋๋ค. ์๋น์ค ์์ปค์ ๊ธฐ๋ณธ ์ง์ ์ ์ ์ผ๋ฐ์ ์ผ๋ก `install` ์ด๋ฒคํธ์ด๋ฉฐ, ์ฌ๊ธฐ์์ ๋ฆฌ์ค๋๋ฅผ ์ค์ ํ๊ณ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ด๊ธฐํํ ์ ์์ต๋๋ค.
- ๋ฉ์์ง ์ ๋ฌ: ์๋น์ค ์์ปค๋ ํญ์ ํ์ฑ ์ํ๊ฐ ์๋๋ฏ๋ก ๋ค๋ฅธ ํ์ฅ ํ๋ก๊ทธ๋จ ๋ถ๋ถ(์: ์ฝํ ์ธ ์คํฌ๋ฆฝํธ, ํ์ , ์ต์ ํ์ด์ง)๊ณผ ์๋น์ค ์์ปค ๊ฐ์ ๋น๋๊ธฐ ๋ฉ์์ง ์ ๋ฌ์ ํฌ๊ฒ ์์กดํด์ผ ํฉ๋๋ค. ํต์ ์ ์ํด `chrome.runtime.sendMessage()` ๋ฐ `chrome.runtime.onMessage()`๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ฉ์์ง ์ฒ๋ฆฌ๊ธฐ๊ฐ ๊ฐ๋ ฅํ๊ณ ์๋น์ค ์์ปค๋ฅผ ํ์ฑํํด์ผ ํ๋ ๊ฒฝ์ฐ์๋ ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ ์ ์๋์ง ํ์ธํฉ๋๋ค.
- ์ํ ๊ด๋ฆฌ: ์๊ตฌ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง๋ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ญ ์ํ๋ฅผ ์ ์งํ ์ ์์ต๋๋ค. ์๋น์ค ์์ปค๋ฅผ ์ฌ์ฉํ๋ฉด ์ด ์ํ๊ฐ ์์ปค๊ฐ ์ข
๋ฃ๋ ๋ ์์ค๋ ์ ์์ต๋๋ค. ์๋น์ค ์์ปค ์ข
๋ฃ๋ฅผ ๋ฐฉ์งํด์ผ ํ๋ ์ํ๋ฅผ ์ ์งํ๋ ค๋ฉด
chrome.storage(local๋๋sync)๋ฅผ ์ฌ์ฉํฉ๋๋ค. - ์๋ช ์ฃผ๊ธฐ ์ธ์: ์๋น์ค ์์ปค ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ดํดํฉ๋๋ค. ํ์ฑํ, ๋นํ์ฑํ ๋ฐ ๋ค์ ์์๋ ์ ์์ต๋๋ค. ์ฝ๋๋ ์ด๋ฌํ ์ ํ์ ์ํํ๊ฒ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด ํ์ฑํ ์ ํญ์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ค์ ๋ฑ๋กํฉ๋๋ค.
- ์:
Manifest V2 (background.js):
chrome.runtime.onInstalled.addListener(() => { console.log('Extension installed. Setting up listeners...'); chrome.alarms.create('myAlarm', { periodInMinutes: 1 }); }); chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'myAlarm') { console.log('Alarm triggered!'); // Perform some background task } });Manifest V3 (service-worker.js):
// Service worker installation chrome.runtime.onInstalled.addListener(() => { console.log('Extension installed. Setting up alarms...'); chrome.alarms.create('myAlarm', { periodInMinutes: 1 }); }); // Event listener for alarms chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'myAlarm') { console.log('Alarm triggered!'); // Perform some background task // Note: If the service worker was terminated, it will be woken up for this event. } }); // Optional: Handle messages from other parts of the extension chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === 'getData') { // Simulate fetching data sendResponse({ data: 'Some data from service worker' }); } return true; // Keep the message channel open for async response });
2. `chrome.webRequest`๋ฅผ `declarativeNetRequest`๋ก ๋์ฒด
`chrome.webRequest` API๋ ๋คํธ์ํฌ ์์ฒญ์ ๊ฐ๋ก์ฑ๊ณ , ์ฐจ๋จํ๊ณ , ์์ ํ๊ณ , ๋ฆฌ๋๋ ์ ํ๋ ๊ด๋ฒ์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ต๋๋ค. Manifest V3์์๋ ๋ณด์ ๋ฐ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ์์ ์ด์ ๋ก ๊ทธ ๊ธฐ๋ฅ์ด ํฌ๊ฒ ์ ํ๋ฉ๋๋ค. ์ฃผ์ ๋์ฒดํ์ `declarativeNetRequest` API์ ๋๋ค.
๋ณ๊ฒฝ ์ด์ ๋ ๋ฌด์์ ๋๊น?
`webRequest` API๋ฅผ ํตํด ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ธ๋ผ์ฐ์ ์์ ์ํ๋ ๋ชจ๋ ๋คํธ์ํฌ ์์ฒญ์ ๊ฒ์ฌํ๊ณ ์์ ํ ์ ์์์ต๋๋ค. ์ด๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ๋ฏผ๊ฐํ ์ฌ์ฉ์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋กํ ์ ์์ผ๋ฏ๋ก ๊ฐ์ธ ์ ๋ณด ๋ณดํธ ์ํ์ ์ผ๊ธฐํ์ต๋๋ค. ๋ํ ๋ชจ๋ ์์ฒญ์ ๋ํ JavaScript ๊ฐ๋ก์ฑ๊ธฐ๋ ์๋๊ฐ ๋๋ฆด ์ ์์ผ๋ฏ๋ก ์ฑ๋ฅ์๋ ์ํฅ์ ๋ฏธ์ณค์ต๋๋ค. `declarativeNetRequest`๋ ๊ฐ๋ก์ฑ๊ธฐ ๋ก์ง์ ๋ธ๋ผ์ฐ์ ์ ๊ธฐ๋ณธ ๋คํธ์ํฌ ์คํ์ผ๋ก ์ฎ๊ธฐ๋ฏ๋ก, ํ์ฅ ํ๋ก๊ทธ๋จ์ด ๋ช ์์ ์ผ๋ก ํ์ฉํ์ง ์๋ ํ ์์ฒญ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ง์ ๋ณผ ์ ์์ผ๋ฏ๋ก ์ฑ๋ฅ์ด ๋ ๋ฐ์ด๋๊ณ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ๊ฐ ํฅ์๋ฉ๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต:
- ์ ์ธ์ ๊ท์น ์ดํด: `declarativeNetRequest`๋ ๋ช ๋ นํ ์ฝ๋ ๋์ ์ ์ธ์ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํฉ๋๋ค. ์ผ์นํ๋ ๋คํธ์ํฌ ์์ฒญ์ ์ํํ ์์ (์: ์ฐจ๋จ, ๋ฆฌ๋๋ ์ , ํค๋ ์์ )์ ์ง์ ํ๋ ๊ท์น ์ธํธ(JSON ๊ฐ์ฒด)๋ฅผ ์ ์ํฉ๋๋ค.
- ๊ท์น ์ ์: ๊ท์น์ ์กฐ๊ฑด(์: URL ํจํด, ๋ฆฌ์์ค ์ ํ, ๋๋ฉ์ธ) ๋ฐ ์์ ์ ์ง์ ํฉ๋๋ค. `webRequest` ์ฐจ๋จ ๋๋ ๋ฆฌ๋๋ ์ ๋ก์ง์ ์ด๋ฌํ ๊ท์น ์ธํธ๋ก ๋ณํํด์ผ ํฉ๋๋ค.
- ๊ท์น ์ ํ: ๋ฑ๋กํ ์ ์๋ ๊ท์น ๋ฐ ๊ท์น ์ธํธ ์์ ๋ํ ์ ํ์ ์ธ์งํ์ญ์์ค. ๋ณต์กํ ํํฐ๋ง ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ ๊ท์น ์ธํธ๋ฅผ ๋์ ์ผ๋ก ์ ๋ฐ์ดํธํด์ผ ํ ์ ์์ต๋๋ค.
- ๋์ ์์ ์์: `webRequest`์ ๋ฌ๋ฆฌ `declarativeNetRequest`๋ ๋์ผํ ๋ฐฉ์์ผ๋ก ์์ฒญ ๋ณธ๋ฌธ ๋๋ ํค๋์ ๋์ ์์ ์ ํ์ฉํ์ง ์์ต๋๋ค. ํ์ฅ ํ๋ก๊ทธ๋จ์ ํต์ฌ ๊ธฐ๋ฅ์ด ์ฌ์ธต์ ์ธ ์์ฒญ ์์ ์ ์์กดํ๋ ๊ฒฝ์ฐ ์ค๊ณ๋ฅผ ์ฌํ๊ฐํ๊ฑฐ๋ ๋์ฒด ์ ๊ทผ ๋ฐฉ์์ ๋ชจ์ํด์ผ ํ ์ ์์ต๋๋ค.
- ์ฐจ๋จ ๋ ๋ฆฌ๋๋ ์ : ์์ฒญ ์ฐจ๋จ์ ๊ฐ๋จํฉ๋๋ค. ๋ฆฌ๋๋ ์ ์ ๊ฒฝ์ฐ ์ URL์ ์ง์ ํ์ฌ `redirect` ์์ ์ ์ฌ์ฉํฉ๋๋ค.
- ํค๋ ์กฐ์: MV3๋ ์์ฒญ ํค๋๋ฅผ ์์ ํ๋ ๋ฐ ์ ํ์ด ์์ต๋๋ค. `declarativeNetRequest`์์ `requestHeaders` ๋ฐ `responseHeaders`๋ฅผ ์ฌ์ฉํ์ฌ ํน์ ํค๋๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ ๊ฑฐํ ์ ์์ง๋ง ๋ณต์กํ ๋ณํ์ ์ง์๋์ง ์์ต๋๋ค.
- ์ฑ๋ฅ ๊ณ ๋ ค ์ฌํญ: ์ผ๋ฐ์ ์ผ๋ก ๋ ๋น ๋ฅด์ง๋ง, ๋ง์ ์์ ๊ท์น์ ๊ด๋ฆฌํ๋ ๊ฒ์ ์ฌ์ ํ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ํจ์จ์ฑ์ ์ํด ๊ท์น ์ธํธ๋ฅผ ์ต์ ํํ์ญ์์ค.
- ์:
Manifest V2 (์ด๋ฏธ์ง ์ฐจ๋จ):
chrome.webRequest.onBeforeRequest.addListener( function(details) { return { cancel: true }; }, { urls: ["*://*.example.com/*.png"] }, ["blocking"] );Manifest V3 (`declarativeNetRequest` ์ฌ์ฉ):
๋จผ์ JSON ํ์ผ(์:
rules.json)์ ๊ท์น์ ์ ์ํฉ๋๋ค.[ { "id": 1, "priority": 1, "action": {"type": "block"}, "condition": { "urlFilter": "*.png", "domains": ["example.com"], "resourceTypes": ["image"] } } ]๊ทธ๋ฐ ๋ค์ ์๋น์ค ์์ปค(๋๋ ์ด๊ธฐ ์ค์ ์คํฌ๋ฆฝํธ)์์:
chrome.runtime.onInstalled.addListener(() => { chrome.declarativeNetRequest.updateDynamicRules({ addRules: [ { "id": 1, "priority": 1, "action": {"type": "block"}, "condition": { "urlFilter": "*.png", "domains": ["example.com"], "resourceTypes": ["image"] } } ], removeRuleIds: [1] // To remove if it already exists }); });
3. ์ฝํ ์ธ ์คํฌ๋ฆฝํธ ์คํ ๋ฐ ํต์ ์ฒ๋ฆฌ
์ฝํ ์ธ ์คํฌ๋ฆฝํธ๋ ์น ํ์ด์ง์ ์ปจํ ์คํธ์์ ์คํ๋๋ JavaScript ํ์ผ์ ๋๋ค. ๊ธฐ๋ณธ ๋ชฉ์ ์ ๋์ผํ๊ฒ ์ ์ง๋์ง๋ง, MV3๋ ์คํ ๋ฐฉ๋ฒ๊ณผ ๋๋จธ์ง ํ์ฅ ํ๋ก๊ทธ๋จ๊ณผ์ ์ํธ ์์ฉ์ ๊ฐ์ ํฉ๋๋ค.
์ฃผ์ ๋ณ๊ฒฝ ์ฌํญ ๋ฐ ์ ๋ต:
- ์คํ ์ปจํ ์คํธ: ์ฝํ ์ธ ์คํฌ๋ฆฝํธ๋ ์ฌ์ ํ ํ์ด์ง์ ์ฝ์ ๋ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ `chrome.scripting.executeScript`๋ฅผ ํตํด JavaScript๋ฅผ ์ง์ ์ฝ์ ํ๋ ๊ธฐ๋ฅ์ด ์ด์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฝ์ ํ๋ ๋ฐ ์ ํธ๋๋ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์์ ๋๋ค.
- ๋น๋๊ธฐ ์ฝ์ : `chrome.scripting.executeScript`๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์คํ์ ๋น๋๊ธฐ์ ์ ๋๋ค. DOM ๋๋ ์ ์ญ ๋ฒ์์ ์ํธ ์์ฉํ๊ธฐ ์ ์ ์คํฌ๋ฆฝํธ๊ฐ ์ฝ์ ๋๊ณ ์คํ๋ ๋๊น์ง ์ฝ๋๊ฐ ๊ธฐ๋ค๋ฆฌ๋์ง ํ์ธํฉ๋๋ค.
- `frameId` ์ธ์: ํ์ฅ ํ๋ก๊ทธ๋จ์ด iframe๊ณผ ์ํธ ์์ฉํ๋ ๊ฒฝ์ฐ ์คํฌ๋ฆฝํธ๋ฅผ ์ฝ์ ํ๊ฑฐ๋ ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ๋ `frameId` ์์ฑ์ ์ผ๋์ ๋์ญ์์ค.
- DOM ์ก์ธ์ค: DOM์ ์ก์ธ์คํ๋ ๊ฒ์ ์ฃผ์ ๊ธฐ๋ฅ์ผ๋ก ๋จ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ DOM ์กฐ์์ด ํธ์คํธ ํ์ด์ง์ ์์ฒด ์คํฌ๋ฆฝํธ์ ๊ฐ์ญํ ๊ฐ๋ฅ์ฑ์ ์ธ์งํ์ญ์์ค.
- ์๋น์ค ์์ปค์์ ํต์ : ์ฝํ ์ธ ์คํฌ๋ฆฝํธ๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฐฑ์๋ ๋ก์ง์ด ํ์ํ ์์ ์ ์ํด ์๋น์ค ์์ปค(๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ด์ง๋ฅผ ๋์ฒด)์ ํต์ ํด์ผ ํฉ๋๋ค. `chrome.runtime.sendMessage()` ๋ฐ `chrome.runtime.onMessage()`๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ์:
์คํฌ๋ฆฝํธ ์ฝ์ ๋ฐ ํต์ (Manifest V3):
// From your popup or options page chrome.scripting.executeScript({ target: { tabId: YOUR_TAB_ID }, files: ['content.js'] }, (results) => { if (chrome.runtime.lastError) { console.error(chrome.runtime.lastError); return; } console.log('Content script injected:', results); // Now communicate with the injected content script chrome.tabs.sendMessage(YOUR_TAB_ID, { action: "processPage" }, (response) => { if (chrome.runtime.lastError) { console.error(chrome.runtime.lastError); return; } console.log('Response from content script:', response); }); }); // In content.js: chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === "processPage") { console.log('Processing page...'); const pageTitle = document.title; // Perform some DOM manipulation or data extraction sendResponse({ success: true, title: pageTitle }); } return true; // Keep the channel open for async response });
4. `eval()` ๋ฐ `new Function()` ์ ๊ฑฐ
๋ณด์์์ ์ด์ ๋ก Manifest V3์์๋ ํ์ฅ ์ฝ๋ ๋ด์์ `eval()` ๋ฐ `new Function()`์ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ธ์ง๋์ด ์์ต๋๋ค. ์ด๋ฌํ ๊ธฐ๋ฅ์ ์์์ ์ฝ๋ ์คํ์ ํ์ฉํ๋ฉฐ, ์ด๋ ์ฌ๊ฐํ ๋ณด์ ์ทจ์ฝ์ ์ด ๋ ์ ์์ต๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต:
- ์ฝ๋ ์ฌ์ค๊ณ: ๊ฐ์ฅ ๊ฐ๋ ฅํ ์๋ฃจ์ ์ ๋์ ์ฝ๋ ์คํ์ ํผํ๋๋ก ์ฝ๋๋ฅผ ์ฌ์ค๊ณํ๋ ๊ฒ์ ๋๋ค. ํจ์ ์ด๋ฆ ๋๋ ์ฝ๋ ์กฐ๊ฐ์ ๋์ ์ผ๋ก ์์ฑํ๋ ๊ฒฝ์ฐ ์ฌ์ ์ ์๋ ๊ตฌ์กฐ, ๊ตฌ์ฑ ๊ฐ์ฒด ๋๋ ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ณ ๋ คํ์ญ์์ค.
- JSON ๊ตฌ๋ฌธ ๋ถ์: `eval()`์ด JSON ๊ตฌ๋ฌธ ๋ถ์์ ์ฌ์ฉ๋ ๊ฒฝ์ฐ `JSON.parse()`๋ก ์ ํํฉ๋๋ค. ์ด๋ JSON ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ํ์ค์ ์ด๊ณ ์์ ํ ๋ฐฉ๋ฒ์ ๋๋ค.
- ๊ฐ์ฒด ๋งคํ: `new Function()`์ด ์ ๋ ฅ์ ๋ฐ๋ผ ๋์ ์ผ๋ก ํจ์๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ๋ ๊ฒฝ์ฐ ๊ฐ์ฒด ๋งต์ ์ฌ์ฉํ๊ฑฐ๋ ์ค์์น ๋ฌธ์ ์ฌ์ฉํ์ฌ ์ ๋ ฅ์ ์ฌ์ ์ ์๋ ํจ์์ ๋งคํํ๋ ๊ฒ์ ์ดํด๋ณด์ญ์์ค.
- ์:
์ด์ (Manifest V2, ๊ถ์ฅํ์ง ์์):
const dynamicFunctionName = 'myDynamicFunc'; const code = 'console.log("Hello from dynamic function!");'; const dynamicFunc = new Function(code); dynamicFunc(); // Or for JSON parsing: const jsonString = '{"key": "value"}'; const jsonData = eval('(' + jsonString + ')'); // Insecure์ดํ(Manifest V3, ์์ ):
// For dynamic functions: function myDynamicFunc() { console.log("Hello from pre-defined function!"); } // If you need to call it dynamically based on a string, you can use an object map: const availableFunctions = { myDynamicFunc: myDynamicFunc }; const functionToCall = 'myDynamicFunc'; if (availableFunctions[functionToCall]) { availableFunctions[functionToCall](); } else { console.error('Function not found'); } // For JSON parsing: const jsonString = '{"key": "value"}'; const jsonData = JSON.parse(jsonString); // Secure and standard console.log(jsonData.key); // "value"
5. ๊ธฐํ ์ค์ํ API ๊ณ ๋ ค ์ฌํญ
Manifest V3๋ ๋ค๋ฅธ ์ฌ๋ฌ API์ ์ํฅ์ ๋ฏธ์น๋ฉฐ, ์ด๋ฌํ ๋ณ๊ฒฝ ์ฌํญ์ ์ธ์ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
- `chrome.tabs` API: `chrome.tabs` API์ ์ผ๋ถ ๋ฉ์๋๋ ํนํ ํญ ์์ฑ ๋ฐ ๊ด๋ฆฌ์ ๊ดํ์ฌ ๋ค๋ฅด๊ฒ ๋์ํ ์ ์์ต๋๋ค. ์ต์ ๊ถ์ฅ ํจํด์ ์ฌ์ฉํ๊ณ ์๋์ง ํ์ธํ์ญ์์ค.
- `chrome.storage` API: `chrome.storage` API(local ๋ฐ sync)๋ ๋๋ถ๋ถ ๋์ผํ๊ฒ ์ ์ง๋๋ฉฐ ์๋น์ค ์์ปค ์ข ๋ฃ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์งํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
- ๊ถํ: ํ์ฅ ํ๋ก๊ทธ๋จ์ ๊ถํ์ ์ฌํ๊ฐํ์ญ์์ค. MV3๋ ํ์ํ ๊ถํ๋ง ์์ฒญํ๋๋ก ๊ถ์ฅํ๋ฉฐ ๋ณด๋ค ์ธ๋ถํ๋ ์ ์ด๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์ฌ์ฉ์ ์ธํฐํ์ด์ค ์์: ํ์ฅ ํ๋ก๊ทธ๋จ ํ์ ๋ฐ ์ต์ ํ์ด์ง๋ ์ฃผ์ UI ์์๋ก ์ ์ง๋ฉ๋๋ค. ์๋ก์ด ์๋น์ค ์์ปค ์ํคํ ์ฒ์์ ์๋ํ๋๋ก ์ ๋ฐ์ดํธ๋์๋์ง ํ์ธํ์ญ์์ค.
๋ง์ด๊ทธ๋ ์ด์ ์ ์ํ ๋๊ตฌ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ง์ด๊ทธ๋ ์ด์ ํ๋ ๊ฒ์ ๋ณต์กํ ํ๋ก์ธ์ค๊ฐ ๋ ์ ์์ต๋๋ค. ๋คํํ ๋ ์ํํ๊ฒ ๋ง๋ค ์ ์๋ ๋๊ตฌ์ ๋ชจ๋ฒ ์ฌ๋ก๊ฐ ์์ต๋๋ค.
- ๊ณต์ ๋ฌธ์: ๋ธ๋ผ์ฐ์ ๊ณต๊ธ์ ์ฒด(ํนํ Chrome ๋ฐ Firefox)์ ๋ฌธ์๋ ๊ธฐ๋ณธ ๋ฆฌ์์ค์ ๋๋ค. Manifest V3 ๋ง์ด๊ทธ๋ ์ด์ ๊ฐ์ด๋๋ฅผ ์ฒ ์ ํ ์ฝ์ด๋ณด์ธ์.
- ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ: ๋์ ๋ธ๋ผ์ฐ์ ์ ๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ํ์ฉํ์ญ์์ค. ์ด๋ ์ค๋ฅ, ์๋น์ค ์์ปค ์๋ช ์ฃผ๊ธฐ ๋ฐ ๋คํธ์ํฌ ํ๋์ ๋ํ ๊ท์คํ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํฉ๋๋ค.
- ์ ์ง์ ๋ง์ด๊ทธ๋ ์ด์ : ๋๊ท๋ชจ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ์๋ ๊ฒฝ์ฐ ์ ์ง์ ๋ง์ด๊ทธ๋ ์ด์ ์ ๋ต์ ๊ณ ๋ คํ์ญ์์ค. ํ ๋ฒ์ ํ๋์ ๊ธฐ๋ฅ ๋๋ API๋ฅผ ๋ง์ด๊ทธ๋ ์ด์ ํ๊ณ , ์ฒ ์ ํ ํ ์คํธํ ๋ค์ ๋ค์ ๋จ๊ณ๋ก ์ด๋ํฉ๋๋ค.
- ์๋ํ๋ ํ ์คํธ: ๊ฐ๋ ฅํ ํ ์คํธ ์ ํ๊ตฐ์ ๊ตฌํํฉ๋๋ค. ์๋ํ๋ ํ ์คํธ๋ ํ๊ท๋ฅผ ํฌ์ฐฉํ๊ณ ๋ง์ด๊ทธ๋ ์ด์ ๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ๋ค์ํ ์๋๋ฆฌ์ค์์ ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ๋ฐ ํ์์ ์ ๋๋ค.
- ์ฝ๋ ๋ฆฐํ ๋ฐ ๋ถ์: MV3 ๊ฐ๋ฐ์ ๋ง๊ฒ ๊ตฌ์ฑ๋ ๋ฆฐํฐ(์: ESLint)๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฌ์ ์ธ ๋ฌธ์ ๋ฅผ ์กฐ๊ธฐ์ ํฌ์ฐฉํฉ๋๋ค.
- ์ปค๋ฎค๋ํฐ ํฌ๋ผ ๋ฐ ์ง์: ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ์ ์ฐธ์ฌํ์ญ์์ค. ๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ ์ฌํ ๋ฌธ์ ์ ์ง๋ฉดํ๊ณ ์์ผ๋ฉฐ, ๊ฒฝํ์ ๊ณต์ ํ๋ฉด ํจ๊ณผ์ ์ธ ์๋ฃจ์ ์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
- ์ฐจ๋จ๋ ๊ธฐ๋ฅ์ ๋ํ ๋์ ๊ณ ๋ ค: ํ์ฅ ํ๋ก๊ทธ๋จ์ ํต์ฌ ๊ธฐ๋ฅ์ด MV3์์ ์ฌ๊ฐํ๊ฒ ์ ํ๋๊ฑฐ๋ ์ ๊ฑฐ๋ API(์: ํน์ `webRequest` ๊ธฐ๋ฅ)์ ์์กดํ๋ ๊ฒฝ์ฐ ๋์ฒด ์ ๊ทผ ๋ฐฉ์์ ํ์ํ์ญ์์ค. ์ฌ๊ธฐ์๋ ์์ง ์ฌ์ฉํ ์ ์๋ ๋ธ๋ผ์ฐ์ API ํ์ฉ, ํด๋ผ์ด์ธํธ ์ธก ํด๋ฆฌ์คํฑ ์ฌ์ฉ ๋๋ ํด๋น ๊ธฐ๋ฅ์ ๊ตฌํ์ ์ฌ๊ณ ํ๋ ๊ฒ์ด ํฌํจ๋ ์ ์์ต๋๋ค.
Manifest V3์ ๋ํ ๊ธ๋ก๋ฒ ๊ณ ๋ ค ์ฌํญ
๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ๋์์ผ๋ก ํ๋ ๊ฐ๋ฐ์๋ก์ MV3์ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ค์ํ ์ง์ญ๊ณผ ์ปจํ ์คํธ์ ์ฌ์ฉ์์๊ฒ ์ด๋ค ์ํฅ์ ๋ฏธ์น ์ ์๋์ง ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
- ๋ค์ํ ์ฅ์น์์ ์ฑ๋ฅ: ์๋น์ค ์์ปค์ ํจ์จ์ฑ ์ฆ๊ฐ๋ ๊ฐ๋ฐ๋์๊ตญ์ ๋น๋กฏํ ๋ง์ ๊ณณ์์ ํํ ์ฌ์ฉ๋๋ ์ ์ ๋ ฅ ์ฅ์น ๋๋ ๋๋ฆฐ ์ธํฐ๋ท ์ฐ๊ฒฐ์ ์ฌ์ฉํ๋ ์ฌ์ฉ์์๊ฒ ํนํ ์ ์ตํฉ๋๋ค.
- ์ ์ธ๊ณ์ ์ธ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ ๋ฌธ์ : MV3์ ๊ฐํ๋ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ๋ ์ ์ธ๊ณ์ ์ธ ๋ฐ์ดํฐ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ ๊ท์ (์: GDPR, CCPA) ๋ฐ ์ฌ์ฉ์ ๊ธฐ๋๋ฅผ ์ถฉ์กฑํฉ๋๋ค. ์ด๋ ๋ค์ํ ์ฌ์ฉ์ ๊ธฐ๋ฐ ์ฌ์ด์์ ๋ ํฐ ์ ๋ขฐ๋ฅผ ์กฐ์ฑํ ์ ์์ต๋๋ค.
- ์น ํ์ค ์ ๋ ฌ: MV3๋ ์ฃผ๋ก Chromium์ ์ํด ์ฃผ๋๋์ง๋ง, ๋ ์์ ํ๊ณ ๊ฐ์ธ ์ ๋ณด๋ฅผ ๋ณดํธํ๋ ์น ํ์ฅ ํ๋ก๊ทธ๋จ ๋ชจ๋ธ๋ก์ ์ ํ์ ๊ธ๋ก๋ฒ ํธ๋ ๋์ ๋๋ค. ์ด๋ฌํ ๋ณํ๋ฅผ ์์๋๊ฐ๋ฉด ๊ด๋ฒ์ํ ํ๋ซํผ ํธํ์ฑ ๋ฐ ๋ฏธ๋ ์น ํ์ค์ ๋ํ ํ์ฅ ํ๋ก๊ทธ๋จ์ ์ค๋นํ ์ ์์ต๋๋ค.
- ๋ฌธ์ ์ ๊ทผ์ฑ: ์์กดํ๋ ๋ง์ด๊ทธ๋ ์ด์ ๋ฆฌ์์ค๊ฐ ์ ๊ทผ ๊ฐ๋ฅํ๊ณ ํ์ํ ๊ฒฝ์ฐ ๋ช ํํ๊ฒ ๋ฒ์ญ๋์๋์ง ํ์ธํ์ญ์์ค. ์ด ๊ฒ์๋ฌผ์ ์์ด๋ก ์์ฑ๋์์ง๋ง, ์ ์ธ๊ณ์ ๊ฐ๋ฐ์๋ ํ์งํ๋ ๋ฆฌ์์ค๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
- ์ง์ญ๋ณ ํ ์คํธ: ํ์ฅ ํ๋ก๊ทธ๋จ์ ๊ธฐ๋ฅ์ด ๋คํธ์ํฌ์ ์ข ์๋๊ฑฐ๋ ์ง์ญ์ ๋ฐ๋ผ ๋ฏธ๋ฌํ UI ์ฐจ์ด๊ฐ ์์ ์ ์๋ ๊ฒฝ์ฐ, ๋ค์ํ ์ง๋ฆฌ์ ์์น ๋ฐ ๋คํธ์ํฌ ์กฐ๊ฑด์์ ํ ์คํธ๋ฅผ ์ํํ๋์ง ํ์ธํ์ญ์์ค.
Manifest V3๋ฅผ ์ฌ์ฉํ ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฏธ๋
Manifest V3๋ ๋จ์ํ ์ ๋ฐ์ดํธ๊ฐ ์๋๋ผ ๋ ์์ ํ๊ณ , ๊ฐ์ธ ์ ๋ณด ๋ณดํธ๊ฐ ๊ฐํ๋๊ณ , ์ฑ๋ฅ์ด ํฅ์๋ ์น ํ์ฅ ํ๋ก๊ทธ๋จ ์ํ๊ณ๋ก์ ์ค์ํ ๋จ๊ณ์ ๋๋ค. ๋ง์ด๊ทธ๋ ์ด์ ์ ์ด๋ ค์์ ์ ์ํ์ง๋ง, ๊ฐ๋ฐ์๊ฐ ๋ ์ข๊ณ ๋ ์ฑ ์๊ฐ ์๋ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๊ตฌ์ถํ ์ ์๋ ๊ธฐํ๋ฅผ ์ ๊ณตํฉ๋๋ค. ํต์ฌ API ๋ณ๊ฒฝ ์ฌํญ์ ์ดํดํ๊ณ ์ ๋ต์ ๋ง์ด๊ทธ๋ ์ด์ ๋ฐฉ์์ ์ฑํํจ์ผ๋ก์จ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ด ๊ด๋ จ์ฑ์ด ์๊ณ ๊ฐ์น ์๊ฒ ์ ์ง๋๋๋ก ํ ์ ์์ต๋๋ค.
์ ํ์ ์์ฉํ๊ณ , ์๋ก์ด ๊ธฐ๋ฅ์ ํ์ฉํ๊ณ , ํ์ ์ ๊ณ์ํ์ญ์์ค. ๋ธ๋ผ์ฐ์ ํ์ฅ ํ๋ก๊ทธ๋จ์ ๋ฏธ๋๊ฐ ์ฌ๊ธฐ์ ์์ผ๋ฉฐ, ๋ณด์๊ณผ ์ฌ์ฉ์ ์ ๋ขฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋์์ต๋๋ค.